#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

#include <psp2/io/dirent.h>
#include <psp2/io/fcntl.h>
#include <psp2/power.h>

#include "menu.h"
#include "ui.h"
#include "config.h"
#include "states.h"
#include "utils.h"
#include "file.h"
#include "browser.h"
#include "shaders.h"
#include "retro.h"
#include "audio.h"
#include "video.h"
#include "init.h"
#include "lang.h"
#include "main.h"
#include "boot.h"

#include "libretro.h"

// Menu
#define MENU_WINDOW_WIDTH 960.0f  // 840.0f
#define MENU_WINDOW_HEIGHT 544.0f // 476.0f
#define MENU_WINDOW_PADDING 0.0f
#define MENU_WINDOW_COLOR COLOR_ALPHA(BLACK, 0xAF)

#define TAB_PADDING_T 8.0f
#define TAB_PADDING_L 10.0f
#define TAB_LINE_HEIGHT 3.0f

#define TAB_FOCUS_BG_COLOR COLOR_ALPHA(AZURE, 0xAF)

#define MENU_ENTRY_LINE_SPACE 6.0f
#define MENU_ENTRY_PADDING_T 8.0f
#define MENU_ENTRY_PADDING_L 10.0f

// Menu free draw
#define MENU_FREE_DRAW_PADDING_T 0.0f
#define MENU_FREE_DRAW_PADDING_L 0.0f

enum MenuEntryControlTypes
{
    MENU_ENTRY_CONTROL_UP,
    MENU_ENTRY_CONTROL_DOWN,
    MENU_ENTRY_CONTROL_L,
    MENU_ENTRY_CONTROL_R,
};

typedef struct
{
    char *desc;
    int enable;
    MenuEntry *entries;
    int n_entries;
} TabEntry;

typedef struct
{
    int relative_top_pos;
    int relative_focus_pos;
    int n_enable_entries;
    int *enable_entry_ids;
} EntriesInfo;

static int saveScreenshot();
static int saveScreenshotForPreview();

static int menuResumeGame();
static int menuResetGame();
static int menuExitGame();
static int menuExitToArch();
static int menuExitApp();

static void enterOption();
static void exitOption();

static void setControlOptionText(ControlOptionValue *option);
static void setControlOptionTexts();

static void MenuRefreshEntryPos(int type, int pos);
static void refreshTabPos();

static KeyMapEntry keymap_entries[] = {
#if defined(WSC_BUILD)
    {"X1", RETRO_DEVICE_ID_JOYPAD_LEFT, 0},
    {"X2", RETRO_DEVICE_ID_JOYPAD_UP, 0},
    {"X3", RETRO_DEVICE_ID_JOYPAD_RIGHT, 0},
    {"X4", RETRO_DEVICE_ID_JOYPAD_DOWN, 0},
#else
    {"←", RETRO_DEVICE_ID_JOYPAD_LEFT, 0},
    {"↑", RETRO_DEVICE_ID_JOYPAD_UP, 0},
    {"→", RETRO_DEVICE_ID_JOYPAD_RIGHT, 0},
    {"↓", RETRO_DEVICE_ID_JOYPAD_DOWN, 0},
#endif
#if defined(FC_BUILD) || defined(GBC_BUILD) || defined(NGP_BUILD)
    {"A", RETRO_DEVICE_ID_JOYPAD_A, 0},
    {"B", RETRO_DEVICE_ID_JOYPAD_B, 0},
    {"Select", RETRO_DEVICE_ID_JOYPAD_SELECT, 0},
    {"Start", RETRO_DEVICE_ID_JOYPAD_START, 0},
#elif defined(SFC_BUILD)
    {"A", RETRO_DEVICE_ID_JOYPAD_A, 0},
    {"B", RETRO_DEVICE_ID_JOYPAD_B, 0},
    {"X", RETRO_DEVICE_ID_JOYPAD_X, 0},
    {"Y", RETRO_DEVICE_ID_JOYPAD_Y, 0},
    {"L", RETRO_DEVICE_ID_JOYPAD_L, 0},
    {"R", RETRO_DEVICE_ID_JOYPAD_R, 0},
    {"Select", RETRO_DEVICE_ID_JOYPAD_SELECT, 0},
    {"Start", RETRO_DEVICE_ID_JOYPAD_START, 0},
#elif defined(GBA_BUILD)
    {"A", RETRO_DEVICE_ID_JOYPAD_A, 0},
    {"B", RETRO_DEVICE_ID_JOYPAD_B, 0},
    {"L", RETRO_DEVICE_ID_JOYPAD_L, 0},
    {"R", RETRO_DEVICE_ID_JOYPAD_R, 0},
    {"Select", RETRO_DEVICE_ID_JOYPAD_SELECT, 0},
    {"Start", RETRO_DEVICE_ID_JOYPAD_START, 0},
#elif defined(MD_BUILD)
    {"A", RETRO_DEVICE_ID_JOYPAD_Y, 0},
    {"B", RETRO_DEVICE_ID_JOYPAD_B, 0},
    {"C", RETRO_DEVICE_ID_JOYPAD_A, 0},
    {"X", RETRO_DEVICE_ID_JOYPAD_L, 0},
    {"Y", RETRO_DEVICE_ID_JOYPAD_X, 0},
    {"Z", RETRO_DEVICE_ID_JOYPAD_R, 0},
    {STR_SWICTH_MODE, RETRO_DEVICE_ID_JOYPAD_SELECT, 0},
    {"Start", RETRO_DEVICE_ID_JOYPAD_START, 0},
#elif defined(WSC_BUILD)
    {"Y1", RETRO_DEVICE_ID_JOYPAD_L, 0},
    {"Y2", RETRO_DEVICE_ID_JOYPAD_R2, 0},
    {"Y3", RETRO_DEVICE_ID_JOYPAD_R, 0},
    {"Y4", RETRO_DEVICE_ID_JOYPAD_L2, 0},
    {"A", RETRO_DEVICE_ID_JOYPAD_A, 0},
    {"B", RETRO_DEVICE_ID_JOYPAD_B, 0},
    {"Start", RETRO_DEVICE_ID_JOYPAD_START, 0},
#elif defined(PCE_BUILD)
    {"A", RETRO_DEVICE_ID_JOYPAD_A, 0},
    {"B", RETRO_DEVICE_ID_JOYPAD_B, 0},
    {"X", RETRO_DEVICE_ID_JOYPAD_X, 0},
    {"Y", RETRO_DEVICE_ID_JOYPAD_Y, 0},
    {"L", RETRO_DEVICE_ID_JOYPAD_L, 0},
    {"R", RETRO_DEVICE_ID_JOYPAD_R, 0},
    {"Select", RETRO_DEVICE_ID_JOYPAD_SELECT, 0},
    {"Start", RETRO_DEVICE_ID_JOYPAD_START, 0},
    {STR_SWICTH_MODE, RETRO_DEVICE_ID_JOYPAD_L2, 0},
#elif defined(ARC_BUILD)
    {"A", RETRO_DEVICE_ID_JOYPAD_B, 0},
    {"B", RETRO_DEVICE_ID_JOYPAD_A, 0},
    {"C", RETRO_DEVICE_ID_JOYPAD_Y, 0},
    {"D", RETRO_DEVICE_ID_JOYPAD_X, 0},
    {"E", RETRO_DEVICE_ID_JOYPAD_L, 0},
    {"F", RETRO_DEVICE_ID_JOYPAD_R, 0},
    {STR_COIN, RETRO_DEVICE_ID_JOYPAD_SELECT, 0},
    {STR_START, RETRO_DEVICE_ID_JOYPAD_START, 0},
#elif defined(PS_BUILD)
    {STR_BUTTON_CROSS, RETRO_DEVICE_ID_JOYPAD_B, 0},
    {STR_BUTTON_CIRCLE, RETRO_DEVICE_ID_JOYPAD_A, 0},
    {STR_BUTTON_SQUARE, RETRO_DEVICE_ID_JOYPAD_Y, 0},
    {STR_BUTTON_TRIANGLE, RETRO_DEVICE_ID_JOYPAD_X, 0},
    {"L", RETRO_DEVICE_ID_JOYPAD_L, 0},
    {"R", RETRO_DEVICE_ID_JOYPAD_R, 0},
    {"L2", RETRO_DEVICE_ID_JOYPAD_L2, 0},
    {"R2", RETRO_DEVICE_ID_JOYPAD_R2, 0},
    {"L3", RETRO_DEVICE_ID_JOYPAD_L3, 0},
    {"R3", RETRO_DEVICE_ID_JOYPAD_R3, 0},
    {"Select", RETRO_DEVICE_ID_JOYPAD_SELECT, 0},
    {"Start", RETRO_DEVICE_ID_JOYPAD_START, 0},
#elif defined(MRP_BUILD)
    {"A", RETRO_DEVICE_ID_JOYPAD_A, 0},
    {"B", RETRO_DEVICE_ID_JOYPAD_B, 0},
    {"X", RETRO_DEVICE_ID_JOYPAD_X, 0},
    {"Y", RETRO_DEVICE_ID_JOYPAD_Y, 0},
    {"L", RETRO_DEVICE_ID_JOYPAD_L, 0},
    {"R", RETRO_DEVICE_ID_JOYPAD_R, 0},
    {"L2", RETRO_DEVICE_ID_JOYPAD_L2, 0},
    {"R2", RETRO_DEVICE_ID_JOYPAD_R2, 0},
    {"L3", RETRO_DEVICE_ID_JOYPAD_L3, 0},
    {"R3", RETRO_DEVICE_ID_JOYPAD_R3, 0},
    {"Select", RETRO_DEVICE_ID_JOYPAD_SELECT, 0},
    {"Start", RETRO_DEVICE_ID_JOYPAD_START, 0},
#else
    {"A", RETRO_DEVICE_ID_JOYPAD_A, 0},
    {"B", RETRO_DEVICE_ID_JOYPAD_B, 0},
    {"X", RETRO_DEVICE_ID_JOYPAD_X, 0},
    {"Y", RETRO_DEVICE_ID_JOYPAD_Y, 0},
    {"L", RETRO_DEVICE_ID_JOYPAD_L, 0},
    {"R", RETRO_DEVICE_ID_JOYPAD_R, 0},
    {"L2", RETRO_DEVICE_ID_JOYPAD_L2, 0},
    {"R2", RETRO_DEVICE_ID_JOYPAD_R2, 0},
    {"L3", RETRO_DEVICE_ID_JOYPAD_L3, 0},
    {"R3", RETRO_DEVICE_ID_JOYPAD_R3, 0},
    {"Select", RETRO_DEVICE_ID_JOYPAD_SELECT, 0},
    {"Start", RETRO_DEVICE_ID_JOYPAD_START, 0},
#endif
};
#define N_OPTION_ENTRIES (sizeof(keymap_entries) / sizeof(KeyMapEntry))

static char *no_yes_values[] = {
    STR_NO,
    STR_YES,
};

static char *screen_size_values[] = {
    STR_SCREEN_SIZE_1X,
    STR_SCREEN_SIZE_2X,
    STR_SCREEN_SIZE_3X,
    STR_SCREEN_SIZE_FIT,
    STR_SCREEN_SIZE_FIT_8_7,
    STR_SCREEN_SIZE_FIT_4_3,
    STR_SCREEN_SIZE_FIT_3_2,
    STR_SCREEN_SIZE_FULL,
};

#if defined(WANT_DISPLAY_ROTATE)
static char *display_rotate_values[] = {
    STR_DISABLE,
    STR_ROTATE_90,
    STR_ROTATE_180,
    STR_ROTATE_270,
};
#endif

static char *graphics_values[] = {
    STR_DEFAULT,
    STR_GRAPHICS_LCD3X,
    STR_GRAPHICS_SHARP_SIMPLE,
    STR_GRAPHICS_SHARP,
    STR_GRAPHICS_AA,
};

static char *show_overlay_values[] = {
    STR_DISABLE,
    STR_OVERLAY_FRONT_MODE,
    STR_OVERLAY_BACK_MODE,
};

static char *left_analog_values[] = {
    STR_DISABLE,
    STR_FOLLOW_DPAD,
#if 0 // defined(PS_BUILD)
	STR_BUTTON_LEFT_ANALOG,
#endif
};

static char *right_analog_values[] = {
    STR_DISABLE,
    STR_FOLLOW_DPAD,
#if 0 // defined(PS_BUILD)
	STR_BUTTON_RIGHT_ANALOG,
#endif
};

static char *preview_path_values[] = {
    STR_AUTO,
    STR_DEFAULT,
    STR_FROM_AUTO_SAVETATE,
};

static char *preview_style_values[] = {
    STR_PRESERVE_FILL,
    STR_FULL_FILL,
};

// 设置
StrOptionValue preview_path_option = {&setting_config.preview_path, preview_path_values, sizeof(preview_path_values) / sizeof(char **)};
StrOptionValue preview_style_option = {&setting_config.preview_style, preview_style_values, sizeof(preview_style_values) / sizeof(char **)};
StrOptionValue app_log_option = {&setting_config.app_log, no_yes_values, sizeof(no_yes_values) / sizeof(char **)};
StrOptionValue core_log_option = {&setting_config.core_log, no_yes_values, sizeof(no_yes_values) / sizeof(char **)};
StrOptionValue loading_log_option = {&setting_config.loading_log, no_yes_values, sizeof(no_yes_values) / sizeof(char **)};

// 游戏
StrOptionValue auto_save_load_option = {&misc_config.auto_save_load, no_yes_values, sizeof(no_yes_values) / sizeof(char **)};

// 图形
StrOptionValue screen_size_option = {&graphics_config.screen_size, screen_size_values, sizeof(screen_size_values) / sizeof(char **)};
#if defined(WANT_DISPLAY_ROTATE)
StrOptionValue display_rotate_option = {&graphics_config.display_rotate, display_rotate_values, sizeof(display_rotate_values) / sizeof(char **)};
#endif
StrOptionValue graphics_filtering_option = {&graphics_config.graphics_filtering, graphics_values, sizeof(graphics_values) / sizeof(char **)};
StrOptionValue smooth_graphics_option = {&graphics_config.smooth_graphics, no_yes_values, sizeof(no_yes_values) / sizeof(char **)};
StrOptionValue show_overlay_option = {&graphics_config.show_overlay, show_overlay_values, sizeof(show_overlay_values) / sizeof(char **)};
StrOptionValue show_fps_option = {&graphics_config.show_fps, no_yes_values, sizeof(no_yes_values) / sizeof(char **)};

// 控制
ControlOptionValue button_left_option = {&control_config.button_left, SCE_CTRL_LEFT, STR_DISABLE};
ControlOptionValue button_up_option = {&control_config.button_up, SCE_CTRL_UP, STR_DISABLE};
ControlOptionValue button_right_option = {&control_config.button_right, SCE_CTRL_RIGHT, STR_DISABLE};
ControlOptionValue button_down_option = {&control_config.button_down, SCE_CTRL_DOWN, STR_DISABLE};
ControlOptionValue button_cross_option = {&control_config.button_cross, SCE_CTRL_CROSS, STR_DISABLE};
ControlOptionValue button_circle_option = {&control_config.button_circle, SCE_CTRL_CIRCLE, STR_DISABLE};
ControlOptionValue button_square_option = {&control_config.button_square, SCE_CTRL_SQUARE, STR_DISABLE};
ControlOptionValue button_triangle_option = {&control_config.button_triangle, SCE_CTRL_TRIANGLE, STR_DISABLE};
ControlOptionValue button_select_option = {&control_config.button_select, SCE_CTRL_SELECT, STR_DISABLE};
ControlOptionValue button_start_option = {&control_config.button_start, SCE_CTRL_START, STR_DISABLE};
ControlOptionValue button_l_option = {&control_config.button_l, SCE_CTRL_L1, STR_DISABLE};
ControlOptionValue button_r_option = {&control_config.button_r, SCE_CTRL_R1, STR_DISABLE};
ControlOptionValue button_l2_option = {&control_config.button_l2, SCE_CTRL_L2, STR_DISABLE};
ControlOptionValue button_r2_option = {&control_config.button_r2, SCE_CTRL_R2, STR_DISABLE};
ControlOptionValue button_l3_option = {&control_config.button_l3, SCE_CTRL_L3, STR_DISABLE};
ControlOptionValue button_r3_option = {&control_config.button_r3, SCE_CTRL_R3, STR_DISABLE};

StrOptionValue left_analog_option = {&control_config.left_analog, left_analog_values, sizeof(left_analog_values) / sizeof(char **)};
StrOptionValue right_analog_option = {&control_config.right_analog, right_analog_values, sizeof(right_analog_values) / sizeof(char **)};
StrOptionValue front_touch_pad_option = {&control_config.front_touch_pad, no_yes_values, sizeof(no_yes_values) / sizeof(char **)};
StrOptionValue back_touch_pad_option = {&control_config.back_touch_pad, no_yes_values, sizeof(no_yes_values) / sizeof(char **)};
IntOptionValue turbo_delay_option = {&control_config.turbo_delay, 1, 30};

// 主菜单
static MenuEntry main_entries[] = {
    {STR_RESUME_GAME, 0, MENU_ENTRY_TYPE_CALLBACK, menuResumeGame},
    {STR_RESET_GAME, 0, MENU_ENTRY_TYPE_CALLBACK, menuResetGame},
    {STR_EXIT_GAME, 0, MENU_ENTRY_TYPE_CALLBACK, menuExitGame},
    {STR_EXIT_TO_ARCH, 1, MENU_ENTRY_TYPE_CALLBACK, menuExitToArch},
    {STR_EXIT_APP, 1, MENU_ENTRY_TYPE_CALLBACK, menuExitApp},
};

//图形
static MenuEntry graphics_entries[] = {
    {STR_SCREEN_SIZE, 1, MENU_ENTRY_TYPE_OPTION_STR, &screen_size_option},
#if defined(WANT_DISPLAY_ROTATE)
    {STR_DISPLAY_ROTATE, 1, MENU_ENTRY_TYPE_OPTION_STR, &display_rotate_option},
#endif
    {STR_GRAPHICS_FILTERING, 1, MENU_ENTRY_TYPE_OPTION_STR, &graphics_filtering_option},
    {STR_GRAPHICS_SMOOTH, 1, MENU_ENTRY_TYPE_OPTION_STR, &smooth_graphics_option},
    {STR_SHOW_OVERLAY, 1, MENU_ENTRY_TYPE_OPTION_STR, &show_overlay_option},
    {STR_SHOW_FPS, 1, MENU_ENTRY_TYPE_OPTION_STR, &show_fps_option},
    {STR_RESET_DEFAULT_CONFIG, 1, MENU_ENTRY_TYPE_CALLBACK, resetGraphicsConfig},
};

// 控制
MenuEntry control_entries[] = {
    //*name   enable    type    *option
    {STR_BUTTON_LEFT, 1, MENU_ENTRY_TYPE_OPTION_CONTROL, &button_left_option},
    {STR_BUTTON_UP, 1, MENU_ENTRY_TYPE_OPTION_CONTROL, &button_up_option},
    {STR_BUTTON_RIGHT, 1, MENU_ENTRY_TYPE_OPTION_CONTROL, &button_right_option},
    {STR_BUTTON_DOWN, 1, MENU_ENTRY_TYPE_OPTION_CONTROL, &button_down_option},
    {STR_BUTTON_CROSS, 1, MENU_ENTRY_TYPE_OPTION_CONTROL, &button_cross_option},
    {STR_BUTTON_CIRCLE, 1, MENU_ENTRY_TYPE_OPTION_CONTROL, &button_circle_option},
    {STR_BUTTON_SQUARE, 1, MENU_ENTRY_TYPE_OPTION_CONTROL, &button_square_option},
    {STR_BUTTON_TRIANGLE, 1, MENU_ENTRY_TYPE_OPTION_CONTROL, &button_triangle_option},
    {STR_BUTTON_L, 1, MENU_ENTRY_TYPE_OPTION_CONTROL, &button_l_option},
    {STR_BUTTON_R, 1, MENU_ENTRY_TYPE_OPTION_CONTROL, &button_r_option},
    {STR_BUTTON_L2, 1, MENU_ENTRY_TYPE_OPTION_CONTROL, &button_l2_option},
    {STR_BUTTON_R2, 1, MENU_ENTRY_TYPE_OPTION_CONTROL, &button_r2_option},
    {STR_BUTTON_L3, 1, MENU_ENTRY_TYPE_OPTION_CONTROL, &button_l3_option},
    {STR_BUTTON_R3, 1, MENU_ENTRY_TYPE_OPTION_CONTROL, &button_r3_option},
    {STR_BUTTON_SELECT, 1, MENU_ENTRY_TYPE_OPTION_CONTROL, &button_select_option},
    {STR_BUTTON_START, 1, MENU_ENTRY_TYPE_OPTION_CONTROL, &button_start_option},
    {STR_BUTTON_LEFT_ANALOG, 1, MENU_ENTRY_TYPE_OPTION_STR, &left_analog_option},
    {STR_BUTTON_RIGHT_ANALOG, 1, MENU_ENTRY_TYPE_OPTION_STR, &right_analog_option},
    {STR_FRONT_TOUCH_PAD_OPTION, 1, MENU_ENTRY_TYPE_OPTION_STR, &front_touch_pad_option},
    {STR_BACK_TOUCH_PAD_OPTION, 1, MENU_ENTRY_TYPE_OPTION_STR, &back_touch_pad_option},
    {STR_TURBO_DELAY, 1, MENU_ENTRY_TYPE_OPTION_INT, &turbo_delay_option},
#if defined(WSC_BUILD)
    {STR_RESET_CONTROL_H_OPTIONS, 1, MENU_ENTRY_TYPE_CALLBACK, resetControlConfig},
    {STR_RESET_CONTROL_V_OPTIONS, 1, MENU_ENTRY_TYPE_CALLBACK, resetControlConfigV},
#else
    {STR_RESET_DEFAULT_CONFIG, 1, MENU_ENTRY_TYPE_CALLBACK, resetControlConfig},
#endif
};

// 核心
MenuEntry *core_entries = NULL;

// 杂项
static MenuEntry misc_entries[] = {
    {STR_AUTO_SAVE_LOAD, 1, MENU_ENTRY_TYPE_OPTION_STR, &auto_save_load_option},
    {STR_DELETE_AUTO_SAVESTATE, 1, MENU_ENTRY_TYPE_CALLBACK, deleteAutoSavestate},
    {STR_SAVE_SCREENSHOT, 0, MENU_ENTRY_TYPE_CALLBACK, saveScreenshot},
    {STR_SAVE_PREVIEW, 0, MENU_ENTRY_TYPE_CALLBACK, saveScreenshotForPreview},
    {STR_RESET_DEFAULT_CONFIG, 1, MENU_ENTRY_TYPE_CALLBACK, resetMiscConfig},
};

// 设置
static MenuEntry setting_entries[] = {
    {STR_PREVIEW_PATH, 1, MENU_ENTRY_TYPE_OPTION_STR, &preview_path_option},
    {STR_PREVIEW_STYLE, 1, MENU_ENTRY_TYPE_OPTION_STR, &preview_style_option},
    {STR_APP_LOG, 1, MENU_ENTRY_TYPE_OPTION_STR, &app_log_option},
    {STR_CORE_LOG, 1, MENU_ENTRY_TYPE_OPTION_STR, &core_log_option},
    {STR_LOADING_LOG, 1, MENU_ENTRY_TYPE_OPTION_STR, &loading_log_option},
    {STR_RESET_DEFAULT_CONFIG, 1, MENU_ENTRY_TYPE_CALLBACK, resetSettingConfig},
};

// 标签
static TabEntry tab_entries[] = {
    {STR_MAIN_ENTRIES, 1, main_entries, sizeof(main_entries) / sizeof(MenuEntry)},
    {STR_STATES, 0, NULL, 0},
    {STR_GRAPHICS, 1, graphics_entries, sizeof(graphics_entries) / sizeof(MenuEntry)},
    {STR_CONTROL, 1, control_entries, sizeof(control_entries) / sizeof(MenuEntry)},
    {STR_CORE, 0, NULL, 0},
    {STR_MISC, 1, misc_entries, sizeof(misc_entries) / sizeof(MenuEntry)},
    {STR_SETTING, 1, setting_entries, sizeof(setting_entries) / sizeof(MenuEntry)},
};
#define N_TAB_ENTRIES (sizeof(tab_entries) / sizeof(TabEntry))

int menu_open = 0;
static int menu_need_refresh = 1;
static int main_core_entries_enable = 0;

static EntriesInfo entries_info = {0};

static int tab_pos = 0;

static int entry_top_pos = 0;
static int entry_focus_pos = 0;

static int option_open = 0;
static int option_top_pos = 0;
static int option_focus_pos = 0;

static int setting_changed = 0;
static int graphics_changed = 0;
static int control_changed = 0;
static int core_changed = 0;
static int misc_changed = 0;

static int config_type = CONFIG_TYPE_MAIN;

float MENU_FREE_DRAW_WIDTH, MENU_FREE_DRAW_HEIGHT;
float MENU_FREE_DRAW_SX, MENU_FREE_DRAW_SY, MENU_FREE_DRAW_DX, MENU_FREE_DRAW_DY;

static float menu_window_sx, menu_window_sy, menu_window_dx, menu_window_dy;
static float tab_view_width, tab_view_height;
static float tab_view_sx, tab_view_sy, tab_view_dx, tab_view_dy, tab_text_sx, tab_text_sy;

static int entry_lines;
static float entry_view_width, entry_view_height, entry_y_space;
static float entry_view_sx, entry_view_sy, entry_view_dx, entry_view_dy;
static float entry_text_sx, entry_text_sy, entry_text_dx, entry_text_dy;
static float entry_scroll_bar_x, entry_scroll_bar_y, entry_scroll_bar_height;

static int option_lines;
static float option_view_width, option_view_height, option_y_space;
static float option_view_sx, option_view_sy, option_view_dx, option_view_dy;
static float option_text_sx, option_text_sy, option_text_dx, option_text_dy;
static float option_view_original_sx;
static float option_scroll_bar_x, option_scroll_bar_y, option_scroll_bar_height;

void initOptionDrawInfo()
{
    option_y_space = entry_y_space;
    option_view_width = 210.0f;
    option_view_height = entry_view_height;
    option_lines = entry_lines;
    option_view_original_sx = SCREEN_WIDTH - option_view_width;
    option_view_sx = SCREEN_WIDTH;
    option_view_sy = MENU_FREE_DRAW_SY;
    option_view_dy = MENU_FREE_DRAW_DY;
    option_text_sy = entry_text_sy;
    option_text_dy = entry_text_dy;

    option_scroll_bar_x = option_view_dx - SCROLL_BAR_WIDTH;
    option_scroll_bar_y = option_view_sy;
    option_scroll_bar_height = option_view_height;
}

void initMenuDrawInfo()
{
    menu_window_sx = (SCREEN_WIDTH - MENU_WINDOW_WIDTH) / 2;
    menu_window_sy = (SCREEN_HEIGHT - MENU_WINDOW_HEIGHT) / 2;
    menu_window_dx = menu_window_sx + MENU_WINDOW_WIDTH;
    menu_window_dy = menu_window_sy + MENU_WINDOW_HEIGHT;

    float line_height = UiGetLineHeight();

    tab_view_width = MENU_WINDOW_WIDTH - MENU_WINDOW_PADDING * 2;
    tab_view_height = line_height + TAB_PADDING_T * 2;
    tab_view_sx = menu_window_sx + MENU_WINDOW_PADDING;
    tab_view_sy = menu_window_sy + MENU_WINDOW_PADDING;
    tab_view_dx = tab_view_sx + tab_view_width;
    tab_view_dy = tab_view_sy + tab_view_height;
    tab_text_sx = tab_view_sx + TAB_PADDING_L;
    tab_text_sy = tab_view_sy + TAB_PADDING_T;

    MENU_FREE_DRAW_WIDTH = MENU_WINDOW_WIDTH - MENU_WINDOW_PADDING * 2 - MENU_FREE_DRAW_PADDING_L * 2;
    MENU_FREE_DRAW_HEIGHT = MENU_WINDOW_HEIGHT - MENU_WINDOW_PADDING * 2 - tab_view_height - TAB_LINE_HEIGHT - MENU_FREE_DRAW_PADDING_T * 2;
    MENU_FREE_DRAW_SX = menu_window_sx + MENU_WINDOW_PADDING + MENU_FREE_DRAW_PADDING_L;
    MENU_FREE_DRAW_SY = tab_view_dy + TAB_LINE_HEIGHT + MENU_FREE_DRAW_PADDING_T;
    MENU_FREE_DRAW_DX = MENU_FREE_DRAW_SX + MENU_FREE_DRAW_WIDTH;
    MENU_FREE_DRAW_DY = MENU_FREE_DRAW_SY + MENU_FREE_DRAW_HEIGHT;

    entry_view_width = MENU_FREE_DRAW_WIDTH;
    entry_view_height = MENU_FREE_DRAW_HEIGHT;
    entry_view_sx = MENU_FREE_DRAW_SX;
    entry_view_sy = MENU_FREE_DRAW_SY;
    entry_view_dx = MENU_FREE_DRAW_DX;
    entry_view_dy = MENU_FREE_DRAW_DY;

    float entry_full_height = entry_view_height - MENU_ENTRY_PADDING_T * 2;
    entry_y_space = line_height + MENU_ENTRY_LINE_SPACE;
    entry_lines = (entry_full_height + MENU_ENTRY_LINE_SPACE) / entry_y_space;

    entry_text_sx = entry_view_sx + MENU_ENTRY_PADDING_L;
    entry_text_sy = entry_view_sy + MENU_ENTRY_PADDING_T;
    entry_text_dx = entry_view_dx - MENU_ENTRY_PADDING_L;
    entry_text_dy = entry_view_dy - MENU_ENTRY_LINE_SPACE / 2;

    entry_scroll_bar_x = entry_view_dx - SCROLL_BAR_WIDTH;
    entry_scroll_bar_y = entry_view_sy;
    entry_scroll_bar_height = entry_view_height;

    initOptionDrawInfo();

    initStatesDrawInfo();
}

int isMenuNeedRefresh()
{
    return menu_need_refresh;
}

void setMenuNeedRefresh(int enable)
{
    menu_need_refresh = enable;
}

static void setChanged(MenuEntry *entries)
{
    if (entries == setting_entries)
    {
        setting_changed = 1;
    }
    else if (entries == misc_entries)
    {
        misc_changed = 1;
    }
    else if (entries == graphics_entries)
    {
        graphics_changed = 1;
        vitaVideoSetVideoNeedRefresh(1);
    }
    else if (entries == control_entries)
    {
        control_changed = 1;
    }
    else if (entries == core_entries)
    {
        core_changed = 1;
        updateCoreOptionsDisplayCallback();
    }
}

void setMainCoreEntiesEnable(int enable)
{
    main_core_entries_enable = enable;
}

int isMainCoreEntiesEnable()
{
    return main_core_entries_enable;
}

void setCoreEntiesInfo(MenuEntry *entries, int n_entries, int enable)
{
    tab_entries[4].entries = entries;
    tab_entries[4].n_entries = n_entries;
    tab_entries[4].enable = enable;
}

int getCoreEntiesLength()
{
    return tab_entries[4].n_entries;
}

MenuEntry *getCurrentMenuEntries()
{
    return tab_entries[tab_pos].entries;
}
int enterMenu()
{
    if (menu_open)
        return 0;

    if (game_loaded)
        config_type = CONFIG_TYPE_GAME;
    else
        config_type = CONFIG_TYPE_MAIN;

    if (currentPathIsFile())
    {
        initStates();
        tab_entries[1].enable = 1;
    }
    else
    {
        tab_entries[1].enable = 0;
        if (tab_pos == 1)
        {
            tab_pos = 0;
            menu_need_refresh = 1;
        }
    }

    if (menu_need_refresh)
    {
        menu_need_refresh = 0;

        if (game_loaded)
        {
            tab_entries[6].enable = 0;
            if (core_entries)
                tab_entries[4].enable = 1;

            main_entries[0].enable = 1;
            main_entries[1].enable = 1;
            main_entries[2].enable = 1;

            misc_entries[2].enable = 1;
            misc_entries[3].enable = 1;
        }
        else
        {
            tab_entries[6].enable = 1;
            if (core_entries && main_core_entries_enable)
                tab_entries[4].enable = 1;
            else
                tab_entries[4].enable = 0;

            main_entries[0].enable = 0;
            main_entries[1].enable = 0;
            main_entries[2].enable = 0;

            misc_entries[2].enable = 0;
            misc_entries[3].enable = 0;
        }

        if (exec_boot_mode == BOOT_MODE_ARCH)
        {
            main_entries[3].enable = 1;
        }
        else
        {
            main_entries[3].enable = 0;
        }

        if (is_vitatv_model)
        {
            control_entries[18].enable = 0;
            control_entries[19].enable = 0;
        }
        else
        {
            control_entries[18].enable = 1;
            control_entries[19].enable = 1;
        }
        tab_pos = 0;
        refreshTabPos();

        setControlOptionTexts();
        setStatesFocusPos(0);
    }

    menu_open = 1;

    if (option_open)
    {
        exitOption();
        initOptionDrawInfo();
    }

    return 0;
}

int exitMenu()
{
    if (!menu_open)
        return 0;

    menu_open = 0;


    if (setting_changed)
    {
        setting_changed = 0;
        saveSettingConfig(config_type);
    }
    if (graphics_changed)
    {
        graphics_changed = 0;
        saveGraphicsConfig(config_type);
    }
    if (control_changed)
    {
        control_changed = 0;
        saveControlConfig(config_type);
    }
    if (core_changed)
    {
        core_changed = 0;
        saveCoreConfig(config_type);
        setRetroVariableUpdate(1);
    }
    if (misc_changed)
    {
        misc_changed = 0;
        saveMiscConfig(config_type);
    }

    if (tab_entries[1].enable)
        finishStates();

    if (game_loaded)
        resumeGame();

    return 0;
}

static int menuResumeGame()
{
    exitMenu();

    return 0;
}

static int menuResetGame()
{
    exitMenu();
    resetGame();

    return 0;
}

static int menuExitGame()
{
    exitMenu();
    exitGame();
    if (exec_boot_mode == BOOT_MODE_GAME)
        restoreBootParams();

    return 0;
}

static int menuExitToArch()
{
    exitMenu();
    exitGame();
    restoreBootParams();

    return 0;
}

static int menuExitApp()
{
    exitMenu();
    exitGame();
    exitApp();

    return 0;
}

int resetSettingConfig()
{
    setDefaultSettingConfig();
    setting_changed = 1;

    return 0;
}

int resetGraphicsConfig()
{
    setDefaultGraphicsConfig();
    graphics_changed = 1;
    vitaVideoSetVideoNeedRefresh(1);

    return 0;
}

int resetControlConfig()
{
    setDefaultControlConfig();
    setControlOptionTexts();
    control_changed = 1;

    return 0;
}

#if defined(WSC_BUILD)
int resetControlConfigV()
{
    setDefaultControlConfigV();
    setControlOptionTexts();
    control_changed = 1;

    return 0;
}
#endif

int resetCoreConfig()
{
    setDefaultCoreConfig();
    core_changed = 1;
    updateCoreOptionsDisplayCallback();

    return 0;
}

int resetMiscConfig()
{
    setDefaultMiscConfig();
    misc_changed = 1;

    return 0;
}

int makeSaveScreenshotPath(char *path)
{
    int i;
    char name[MAX_NAME_LENGTH];
    makeCurFileName(name);
    char base_name[MAX_NAME_LENGTH];
    makeBaseName(base_name, name, MAX_NAME_LENGTH);
    for (i = 0; i < 1000; i++)
    {
        snprintf(path, MAX_PATH_LENGTH, "%s/%s_%d.png", (CORE_SCREENSHOTS_DIR), base_name, i);
        if (!checkFileExist(path))
            return 1;
    }

    return 0;
}

void refreshMenuEntriesInfo()
{
    if (entries_info.enable_entry_ids)
        free(entries_info.enable_entry_ids);
    memset(&entries_info, 0, sizeof(EntriesInfo));

    MenuEntry *entries = tab_entries[tab_pos].entries;
    if (!entries)
        return;

    int n_entries = tab_entries[tab_pos].n_entries;

    int i, j;
    for (i = 0; i < n_entries; i++)
    {
        if (entries[i].enable)
            entries_info.n_enable_entries++;
    }

    entries_info.enable_entry_ids = (int *)malloc(entries_info.n_enable_entries * sizeof(int));
    if (!entries_info.enable_entry_ids)
        return;

    for (i = 0, j = 0; i < n_entries; i++)
    {
        if (entries[i].enable)
        {
            entries_info.enable_entry_ids[j] = i;
            j++;
        }
    }

    MenuRefreshEntryPos(MENU_ENTRY_CONTROL_DOWN, entry_focus_pos);
}

static void MenuRefreshEntryPos(int type, int pos)
{
    MenuEntry *entries = tab_entries[tab_pos].entries;
    if (!entries)
        return;

    int n_entries = tab_entries[tab_pos].n_entries;

    int i;
    if (type == MENU_ENTRY_CONTROL_DOWN)
    {
        for (i = pos; i < n_entries; i++)
        {
            if (entries[i].enable)
            {
                entry_focus_pos = i;
                break;
            }
        }
    }
    else if (type == MENU_ENTRY_CONTROL_UP)
    {
        for (i = pos; i >= 0; i--)
        {
            if (entries[i].enable)
            {
                entry_focus_pos = i;
                break;
            }
        }
    }

    if (!entries_info.enable_entry_ids)
        return;

    for (i = 0; i < entries_info.n_enable_entries; i++)
    {
        if (entry_focus_pos == entries_info.enable_entry_ids[i])
        {
            entries_info.relative_focus_pos = i;
            break;
        }
    }

    refreshListPos(&entries_info.relative_top_pos, &entries_info.relative_focus_pos, entries_info.n_enable_entries, entry_lines);
    entry_top_pos = entries_info.enable_entry_ids[entries_info.relative_top_pos];
    entry_focus_pos = entries_info.enable_entry_ids[entries_info.relative_focus_pos];
}

static void refreshTabPos()
{
    entry_top_pos = 0;
    entry_focus_pos = 0;
    refreshMenuEntriesInfo();
}

static void setControlOptionText(ControlOptionValue *option)
{
    uint32_t value = *(option->value);
    char *desc = option->desc;

    desc[0] = '\0';

    if (value & ENABLE_BUTTON_MASK)
    {
        int i;
        uint32_t key = (value & 0x00FFFFFF);
        int n_maped_keys = 0;
        for (i = 0; i < N_OPTION_ENTRIES; i++)
        {
            if (key & RETRO_KEY_BITMASK(keymap_entries[i].core_key))
            {
                if (n_maped_keys > 0)
                    strcat(desc, "+");
                strcat(desc, keymap_entries[i].desc);
                n_maped_keys++;
            }
        }
    }
    else
    {
        strcpy(desc, STR_DISABLE);
    }
}

static void setControlOptionTexts()
{
    int i;
    for (i = 0; i < PAD_PSBUTTON; i++)
    {
        ControlOptionValue *option = (ControlOptionValue *)control_entries[i].option;
        setControlOptionText(option);
    }
}

static void setControlOptionKey(ControlOptionValue *option)
{
    int i;
    uint32_t key = 0;
    uint32_t *value = option->value;
    int turbo = *value & TURBO_BUTTON_MASK;
    for (i = 0; i < N_OPTION_ENTRIES; i++)
    {
        if (keymap_entries[i].selected)
            key |= RETRO_KEY_BITMASK(keymap_entries[i].core_key);
    }
    if (key > 0)
        key |= ENABLE_BUTTON_MASK;
    if (turbo)
        key |= TURBO_BUTTON_MASK;
    *value = key;

    setControlOptionText(option);
    control_changed = 1;
}

int saveScreenshotToPath(const char *path)
{
    int ret = 0;

    char parent_path[MAX_PATH_LENGTH];
    makeBaseDirectory(parent_path, path, MAX_PATH_LENGTH);
    createFolder(parent_path);

    uint32_t base_width, base_height;
    vitaVideoMakeBaseWH(&base_width, &base_height);

    uint32_t screenshot_width, screenshot_height;
    if (graphics_config.display_rotate == 1 || graphics_config.display_rotate == 3)
    {
        screenshot_width = base_height;
        screenshot_height = base_width;
    }
    else
    {
        screenshot_width = base_width;
        screenshot_height = base_height;
    }

    uint64_t screenshot_size = 0;
    uint32_t *screenshot_buf = vitaVideoGetScreenshot(&screenshot_width, &screenshot_height, &screenshot_size);
    if (!screenshot_buf)
        return -1;

    ret = writePngFile(path, (unsigned char *)screenshot_buf, screenshot_width, screenshot_height, 8);
    free(screenshot_buf);

    return ret;
}

static int saveScreenshot()
{
    char path[MAX_PATH_LENGTH];
    if (!makeSaveScreenshotPath(path))
        return -1;

    if (saveScreenshotToPath(path) < 0)
        return -1;

    exitMenu();
    return 0;
}

static int saveScreenshotForPreview()
{
    char path[MAX_PATH_LENGTH];
    makePreviewPath(path);
    if (saveScreenshotToPath(path) < 0)
        return -1;

    unloadPreview();
    exitMenu();
    return 0;
}

static void enterOption()
{
    option_open = 1;
    option_top_pos = 0;
    option_focus_pos = 0;

    option_view_sx = SCREEN_WIDTH;
    ControlOptionValue *option = (ControlOptionValue *)control_entries[entry_focus_pos].option;
    uint32_t value = *(option->value) & 0x00FFFFFF;

    int i;
    for (i = 0; i < N_OPTION_ENTRIES; i++)
    {
        if (value & RETRO_KEY_BITMASK(keymap_entries[i].core_key))
            keymap_entries[i].selected = 1;
        else
            keymap_entries[i].selected = 0;
    }
}

static void exitOption()
{
    option_open = 0;
}

static void drawOptions()
{
    if (option_open)
    {
        if (option_view_sx > option_view_original_sx)
            option_view_sx -= 22;
        if (option_view_sx < option_view_original_sx)
            option_view_sx = option_view_original_sx;
    }
    else
    {
        if (option_view_sx < SCREEN_WIDTH)
            option_view_sx += 22;
        if (option_view_sx >= SCREEN_WIDTH)
        {
            option_view_sx = SCREEN_WIDTH;
            return;
        }
    }

    option_view_dx = option_view_sx + option_view_width;
    float line_height = UiGetLineHeight();
    float mark_width = line_height - 4;
    float mark_sx = option_view_dx - mark_width - MENU_ENTRY_PADDING_L;
    float mark_sy;
    option_text_sx = option_view_sx + MENU_ENTRY_PADDING_L;

    float sx = option_text_sx;
    float sy = option_text_sy;

    vita2d_draw_rectangle(option_view_sx, option_view_sy, option_view_width, option_view_height, COLOR_ALPHA(BLACK, 0xBF));

    int i;
    int drawn_lines = 0;
    for (i = option_top_pos; i < N_OPTION_ENTRIES; i++)
    {
        if (drawn_lines >= option_lines)
            break;

        // Focus
        if (i == option_focus_pos)
            vita2d_draw_rectangle(option_view_sx + 4, sy - (MENU_ENTRY_LINE_SPACE / 2), option_view_width - 8, option_y_space, COLOR_ALPHA(AZURE, 0xBF));

        UiDrawText(sx, sy, GREEN, keymap_entries[i].desc);

        mark_sy = sy + 2;
        vita2d_draw_empty_rectangle(mark_sx, mark_sy, mark_width, mark_width, 1.0f, GREEN);
        if (keymap_entries[i].selected)
            vita2d_draw_rectangle(mark_sx + 1, mark_sy + 1, mark_width - 2, mark_width - 2, COLOR_ALPHA(ORANGE, 0xBF));

        sy += option_y_space;
        drawn_lines++;
    }

    drawScrollBar(option_scroll_bar_x, option_scroll_bar_y, option_scroll_bar_height, option_lines, N_OPTION_ENTRIES, option_top_pos);
}

static void controlOptions()
{
    if (hold_pad[PAD_UP] || hold2_pad[PAD_LEFT_ANALOG_UP])
    {
        option_focus_pos--;
        refreshListPos(&option_top_pos, &option_focus_pos, N_OPTION_ENTRIES, option_lines);
    }
    else if (hold_pad[PAD_DOWN] || hold2_pad[PAD_LEFT_ANALOG_DOWN])
    {
        option_focus_pos++;
        refreshListPos(&option_top_pos, &option_focus_pos, N_OPTION_ENTRIES, option_lines);
    }

    if (released_pad[PAD_SQUARE] || released_pad[PAD_ENTER])
    {
        keymap_entries[option_focus_pos].selected = !keymap_entries[option_focus_pos].selected;
        ControlOptionValue *option = (ControlOptionValue *)control_entries[entry_focus_pos].option;
        setControlOptionKey(option);
    }

    if (released_pad[PAD_TRIANGLE])
    {
        int i;
        for (i = 0; i < N_OPTION_ENTRIES; i++)
            keymap_entries[i].selected = 0;
        ControlOptionValue *option = (ControlOptionValue *)control_entries[entry_focus_pos].option;
        setControlOptionKey(option);
    }

    if (released_pad[PAD_CANCEL])
    {
        exitOption();
    }
}

static void drawEntries()
{
    int i;
    float sx = entry_text_sx;
    float sy = entry_text_sy;
    MenuEntry *entries = tab_entries[tab_pos].entries;

    // Draw entries
    if (entries)
    {
        int n_entries = tab_entries[tab_pos].n_entries;
        float line_height = UiGetLineHeight();

        int drawn_lines = 0;
        for (i = entry_top_pos; i < n_entries; i++)
        {
            if (drawn_lines >= entry_lines)
                break;

            if (!entries[i].enable)
                continue;

            // Focus
            if (i == entry_focus_pos)
                vita2d_draw_rectangle(entry_view_sx, sy - (MENU_ENTRY_LINE_SPACE / 2), entry_view_width, entry_y_space, TAB_FOCUS_BG_COLOR);

            if (entries[i].desc)
                UiDrawText(sx, sy, WHITE, entries[i].desc);

            if (entries[i].type == MENU_ENTRY_TYPE_OPTION_STR) // Option string
            {
                StrOptionValue *option = (StrOptionValue *)entries[i].option;
                int value = *(option->value);
                const char *desc = option->descs[value];
                UiDrawText(entry_text_dx - UiGetTextWidth(desc), sy, GREEN, desc);
            }
            else if (entries[i].type == MENU_ENTRY_TYPE_OPTION_INT) // Option int
            {
                IntOptionValue *option = (IntOptionValue *)entries[i].option;
                int value = *(option->value);
                char value_str[256];
                snprintf(value_str, 256, "%d", value);
                UiDrawText(entry_text_dx - UiGetTextWidth(value_str), sy, GREEN, value_str);
            }
            else if (entries[i].type == MENU_ENTRY_TYPE_OPTION_CONTROL) // Option control
            {
                ControlOptionValue *option = (ControlOptionValue *)entries[i].option;
                int turbo = *(option->value) & TURBO_BUTTON_MASK;
                uint32_t bg_color = turbo ? COLOR_ALPHA(ORANGE, 0xBF) : COLOR_ALPHA(BLACK, 0xBF);
                uint32_t text_color = turbo ? WHITE : DARKGRAY;
                int turbo_text_width = UiGetTextWidth(STR_TURBO);
                int turbo_sx = entry_text_dx - turbo_text_width;
                vita2d_draw_rectangle(turbo_sx, sy, turbo_text_width, line_height, bg_color);
                UiDrawText(turbo_sx, sy, text_color, STR_TURBO);
                UiDrawText(turbo_sx - UiGetTextWidth(option->desc) - 6, sy, GREEN, option->desc);
            }
            else if (entries[i].type == MENU_ENTRY_TYPE_OPTION_CORE) // Option core
            {
                CoreOptionValue *option = (CoreOptionValue *)entries[i].option;
                if (option)
                {
                    const char *label = NULL;
                    if (option->labels && option->labels[option->pos])
                        label = option->labels[option->pos];
                    else if (option->values && option->values[option->pos])
                        label = option->values[option->pos];
                    if (label)
                        UiDrawText(entry_text_dx - UiGetTextWidth(label), sy, GREEN, label);
                }
            }
            sy += entry_y_space;
            drawn_lines++;
        }
        drawScrollBar(entry_scroll_bar_x, entry_scroll_bar_y, entry_scroll_bar_height, entry_lines, entries_info.n_enable_entries, entries_info.relative_top_pos);
    }
}

static void ctrlCommon()
{
    if (!isSkipPressedPsbutton() && released_pad[PAD_PSBUTTON])
    {
        if (option_open)
        {
            exitOption();
        }
        else
        {
            if (tab_pos != 0)
            {
                tab_pos = 0;
                refreshTabPos();
            }
            else
            {
                exitMenu();
            }
        }
        return;
    }

    if (released_pad[PAD_SELECT])
    {
        if (exec_boot_mode == BOOT_MODE_ARCH && !game_loaded)
            menuExitToArch();
        else
            menuExitGame();
        return;
    }
    else if (released_pad[PAD_START])
    {
        menuExitApp();
        return;
    }

    if (option_open)
        return;

    if (released_pad[PAD_L1])
    {
        int i;
        for (i = tab_pos - 1; i != tab_pos; i--)
        {
            if (i < 0)
                i = N_TAB_ENTRIES - 1;
            if (tab_entries[i].enable)
            {
                tab_pos = i;
                refreshTabPos();
                break;
            }
        }
    }
    else if (released_pad[PAD_R1])
    {
        int i;
        for (i = tab_pos + 1; i != tab_pos; i++)
        {
            if (i > N_TAB_ENTRIES - 1)
                i = 0;
            if (tab_entries[i].enable)
            {
                tab_pos = i;
                refreshTabPos();
                break;
            }
        }
    }
}

static void ctrlEntries()
{
    MenuEntry *entries = tab_entries[tab_pos].entries;
    int n_entries = tab_entries[tab_pos].n_entries;

    if (hold_pad[PAD_UP] || hold2_pad[PAD_LEFT_ANALOG_UP])
    {
        MenuRefreshEntryPos(MENU_ENTRY_CONTROL_UP, entry_focus_pos - 1);
    }
    else if (hold_pad[PAD_DOWN] || hold2_pad[PAD_LEFT_ANALOG_DOWN])
    {
        MenuRefreshEntryPos(MENU_ENTRY_CONTROL_DOWN, entry_focus_pos + 1);
    }

    if (entries[entry_focus_pos].type == MENU_ENTRY_TYPE_CALLBACK)
    {
        int (*callback)() = (int (*)())entries[entry_focus_pos].option;
        if (released_pad[PAD_ENTER])
        {
            if (callback)
                callback();
        }
    }
    else if (entries[entry_focus_pos].type == MENU_ENTRY_TYPE_OPTION_STR)
    {
        StrOptionValue *option = (StrOptionValue *)entries[entry_focus_pos].option;
        if (released_pad[PAD_RIGHT] || released_pad[PAD_LEFT_ANALOG_RIGHT] || released_pad[PAD_ENTER])
        {
            if ((*(option->value)) < option->n_options - 1)
                (*(option->value))++;
            else
                (*(option->value)) = 0;
            setChanged(entries);
        }
        else if (released_pad[PAD_LEFT] || released_pad[PAD_LEFT_ANALOG_LEFT])
        {
            if ((*(option->value)) > 0)
                (*(option->value))--;
            else
                (*(option->value)) = option->n_options - 1;
            setChanged(entries);
        }
    }
    else if (entries[entry_focus_pos].type == MENU_ENTRY_TYPE_OPTION_INT)
    {
        IntOptionValue *option = (IntOptionValue *)entries[entry_focus_pos].option;
        if (released_pad[PAD_RIGHT] || released_pad[PAD_LEFT_ANALOG_RIGHT] || released_pad[PAD_ENTER])
        {
            if ((*(option->value)) < option->max)
                (*(option->value))++;
            else
                (*(option->value)) = option->min;
            setChanged(entries);
        }
        else if (released_pad[PAD_LEFT] || released_pad[PAD_LEFT_ANALOG_LEFT])
        {
            if ((*(option->value)) > option->min)
                (*(option->value))--;
            else
                (*(option->value)) = option->max;
            setChanged(entries);
        }
    }
    else if (entries[entry_focus_pos].type == MENU_ENTRY_TYPE_OPTION_CONTROL)
    {
        ControlOptionValue *option = (ControlOptionValue *)entries[entry_focus_pos].option;
        if (released_pad[PAD_SQUARE])
        {
            uint32_t *value = option->value;
            int turbo = !(*value & TURBO_BUTTON_MASK);
            *value = turbo ? (*value | TURBO_BUTTON_MASK) : (*value & ~TURBO_BUTTON_MASK);

            setChanged(entries);
        }

        if (released_pad[PAD_ENTER])
        {
            enterOption();
        }
    }
    else if (entries[entry_focus_pos].type == MENU_ENTRY_TYPE_OPTION_CORE)
    {
        CoreOptionValue *option = (CoreOptionValue *)entries[entry_focus_pos].option;
        if (released_pad[PAD_RIGHT] || released_pad[PAD_LEFT_ANALOG_RIGHT] || released_pad[PAD_ENTER])
        {
            if (option->pos < option->n_options - 1)
                option->pos++;
            else
                option->pos = 0;
            setChanged(entries);
        }
        else if (released_pad[PAD_LEFT] || released_pad[PAD_LEFT_ANALOG_LEFT])
        {
            if (option->pos > 0)
                option->pos--;
            else
                option->pos = option->n_options - 1;
            setChanged(entries);
        }
    }

    if (released_pad[PAD_CANCEL])
    {
        exitMenu();
    }
}

static void drawCommon()
{
    int i;
    float view_sx = tab_view_sx;
    float view_sy = tab_view_sy;
    float text_sx = tab_text_sx;
    float text_sy = tab_text_sy;
    vita2d_draw_rectangle(menu_window_sx, menu_window_sy, MENU_WINDOW_WIDTH, MENU_WINDOW_HEIGHT, MENU_WINDOW_COLOR);
    for (i = 0; i < N_TAB_ENTRIES; i++)
    {
        if (!tab_entries[i].enable)
            continue;

        float text_width = (float)UiGetTextWidth(tab_entries[i].desc);
        float view_width = text_width + TAB_PADDING_L * 2;
        if (i == tab_pos)
            vita2d_draw_rectangle(view_sx, view_sy, view_width, tab_view_height, TAB_FOCUS_BG_COLOR);

        UiDrawText(text_sx, text_sy, WHITE, tab_entries[i].desc);
        view_sx += view_width;
        text_sx += view_width;
    }
    vita2d_draw_rectangle(tab_view_sx, tab_view_dy, tab_view_width, TAB_LINE_HEIGHT, TAB_FOCUS_BG_COLOR);

    if (game_loaded)
    {
        text_sx = tab_view_dx - TAB_PADDING_L;
        text_sy = tab_text_sy;

        if (!is_vitatv_model)
        {
            uint32_t color;
            if (scePowerIsBatteryCharging())
                color = YELLOW;
            else if (scePowerIsLowBattery())
                color = RED;
            else
                color = GREEN;

            int percent = scePowerGetBatteryLifePercent();
            char battery_string[24];
            snprintf(battery_string, sizeof(battery_string), "%d%%", percent);
            text_sx -= UiGetTextWidth(battery_string);
            UiDrawText(text_sx, text_sy, color, battery_string);
            text_sx -= TAB_PADDING_L;
        }

        // time
        SceDateTime time;
        sceRtcGetCurrentClock(&time, 0);

        char time_string[16];
        getTimeString(time_string, time_format, &time);

        text_sx -= UiGetTextWidth(time_string);
        UiDrawText(text_sx, text_sy, DEFALUT_FONT_COLOR, time_string);
    }
}

void drawMenu()
{
    drawCommon();
    if (tab_pos == 1)
        drawStates();
    else
        drawEntries();

    drawOptions();
}

void ctrlMenu()
{
    if (option_open)
    {
        controlOptions();
    }
    else
    {
        if (tab_pos == 1)
            ctrlStates();
        else
            ctrlEntries();
    }
    ctrlCommon();
}
